//
//  STRewardedAdmobObject.swift
//  iPhone
//
//  Created by Toj on 3/30/23.
//

import UIKit
import GoogleMobileAds

class STRewardedAdmobObject: STAdmobObject {
    
    typealias AdObject = GADRewardedAd
    
    /* 广告展示开始时间: 用来报数展示多长时间 */
    private var startTime: CFAbsoluteTime = 0
    
    /* 广告状态 */
    private var loadState: STAdmobAdState = .normal
    
    /*
     * 预加载广告数据: 用来预加载 广告平台对象
     * 本地只缓存第一次预加载的广告, 只要不卸载App 不会被替换
     */
    private var _preloadAdmobModel: STAdmobModel?
    
    /*
     * 预加载广告对象: 借助广告数据加载后的 广告平台对象
     * 预加载只使用 _preloadRewardAdModel做预加载
     * 1. app启动预加载 preloadRewardAdModel
     * 2. 启动的预加载为nil, preloadRewardAdModel先赋值后在预加载
     * 3. 广告dismiss退出后预加载 preloadRewardAdModel
     */
    private var _preloadedGAd: AdObject? { didSet {
        guard _preloadedGAd != nil else {
            loadState.remove([.preloading,.preloaded])
            return
        }
        loadState.remove(.preloading)
        loadState.insert(.preloaded)
    } }
    
    /* 加载广告数据: 用来加载 广告平台对象 */
    private var _admobModel: STAdmobModel?
    /* 广告对象: 借助广告数据加载后的 广告平台对象 */
    private var _loadedGAd: AdObject? { didSet {
        guard let _ = _loadedGAd else {
            loadState.remove([.loading,.loaded, .showing, .showed])
            return
        }
        _loadedGAd?.fullScreenContentDelegate = self
        loadState.remove(.loading)
        loadState.insert(.loaded)
    } }
    
    // 加载过程很长大于15秒 取消界面loading状态, 但是后台还是在loading, 如果成功会弹出
    private let loadingTimeout: TimeInterval = 15
    private var loadingTimer: Timer?
}

extension STRewardedAdmobObject: STAdmobProtocol {
    
    var delegate: STAdmobObjectDelegate? {
        get { return _delegate }
        set { _delegate = newValue }
    }
    
    /*
     * 读取是否有 预加载完成的 广告对象
     */
    func isPreparedAd(admobModel: STAdmobModel) -> Bool {
        let isPrepared = _preloadedGAd != nil
        if isPrepared {
            responseLoadAd(admobModel: admobModel, adObject: _preloadedGAd, error: nil)
            _preloadedGAd = nil
        }
        return isPrepared
    }
    
    /* 预加载 广告对象 */
    func preloadCacheAd(admobModel: STAdmobModel) {
        print("-->toj: admob激励广告 准备预加载广告")
        if loadState.isPreload { return }
        loadState.insert(.preloading)
        
        print("-->toj: admob激励广告 预加载广告")
        requestLoadAd(admobModel: admobModel) { [weak self] ad, error in
            self?.responsePreloadAd(admobModel: admobModel, adObject: ad, error: error)
            print("-->toj: admob激励广告 预加载广告 完成")
        }
    }
    
    /* 更新预加载 广告数据 并且预加载 广告对象 */
    func replacePreloadCacheAd(admobModel: STAdmobModel, completion: ((Bool) -> Void)?) {
        print("-->toj: admob激励广告 更新预加载广告")
        _preloadedGAd = nil
        
        loadState.insert(.preloading)
        print("-->toj: admob激励广告 更新后预加载广告")
        requestLoadAd(admobModel: admobModel) { [weak self] ad, error in
            self?.responsePreloadAd(admobModel: admobModel, adObject: ad, error: error)
            let isSuccess = ad != nil
            completion?(isSuccess)
        }
    }
  
    /*
     * 展示 预加载 广告对象,
     * 有预加载 广告对象: 待展示
     * 无预加载 广告对象: 加载 广告对象, 加载完后缓存广告对象 待展示
     */
    func preloadAd(admobModel: STAdmobModel, completion: ((Bool) -> Void)?) {
        print("-->toj: admob激励广告 准备预加载广告")
        let preadUnitID = _preloadedGAd?.adUnitID
        let materials = admobModel.materials
        if let gad = _preloadedGAd, preadUnitID == materials {
            print("-->toj: admob激励广告 有 预缓存对象")
            if loadState.isLoading { return }
            loadState.insert(.loading)
            print("-->toj: admob激励广告 有 预缓存对象, 待展示")
            
            // 更新最新广告对象
            // 保存广告数据
            responseLoadAd(admobModel: admobModel, adObject: gad, error: nil)
            // 清空预缓存对象
            _preloadedGAd = nil
            
            completion?(true)
            return
        }
        
        print("-->toj: admob激励广告 无 预缓存对象, 开始缓存广告对象")
        
        // 最新广告对象的materials 与预加载的广告不一致, 加载广告新广告
        guard let _ = UIApplication.shared.keyWindow else { return }
        if admobModel.isHUD {
            startLoadingTimer()
            // window.hud.enabled(false).show()
        }
        
        loadAd(admobModel: admobModel) { [weak self] isSuccess in
            if admobModel.isHUD {
                self?.stopLoadingTimer()
                // window.hud.hide()
            }
            completion?(isSuccess)
        }
    }
    
    /* 加载新广告 */
    func loadAd(admobModel: STAdmobModel, completion: ((Bool) -> Void)?) {
        print("-->toj: admob激励广告 准备加载全新广告")
        if loadState.isLoading { return }
        loadState.insert(.loading)
        print("-->toj: admob激励广告 开始加载最新广告")
        requestLoadAd(admobModel: admobModel) { [weak self] ad, error in
            self?.responseLoadAd(admobModel: admobModel, adObject: ad, error: error)
            let isSuccess = ad != nil
            completion?(isSuccess)
        }
    }
    
    /* 展示广告 */
    func presentAd(from vc: UIViewController) {
        print("-->toj: admob激励广告 广告对象即将显示.")
        
        if !loadState.isLoaded {
            if loadState.isShowed {
                print("-->toj: admob激励广告 广告对象已经展示.")
                return
            }
            print("-->toj: admob激励广告 广告对象正在加载.")
            return
        }
        
        print("-->toj: admob激励广告 展示")
        
        _admobModel?.isShowed = false
        // 有待展示广告
        _loadedGAd?.present(fromRootViewController: vc, userDidEarnRewardHandler: { [weak self] in
            self?.userDidEarnRewardHandler()
        })
    }
}

private extension STRewardedAdmobObject {
    
    func requestLoadAd(admobModel: STAdmobModel,
                       completion: @escaping ((_ ad: AdObject?, _ error: Error?)->Void)) {
        print("-->toj: admob激励广告 加载广告对象")
        // 缓存广告对象.adUnitID == 要加载的广告adUnitID, 不需要再加载
        if _preloadedGAd?.adUnitID == admobModel.materials {
            completion(_preloadedGAd, nil)
            print("-->toj: admob激励广告 广告对象可以复用")
            return
        }
        
        AdObject.load(withAdUnitID: admobModel.materials, request: GADRequest()) { ad, error in
            print("-->toj: admob激励广告 新广告对象返回")
            completion(ad, error)
        }
    }
    
    /* 预加载广告回调 */
    func responsePreloadAd(admobModel: STAdmobModel,
                           adObject: AdObject?,
                           error: Error?) {
        print("-->toj: admob激励广告 预加载广告 响应")
        guard _preloadedGAd == nil else { return }
        _preloadedGAd = adObject
        
        if let error = error {
             // self?._preloadRewardAdModel = nil
            print("-->toj: admob激励广告 预加载广告 响应 失败: \(error.localizedDescription). unitID: \(admobModel.materials)")
            return
        }
        
        guard _preloadAdmobModel == nil else { return }
        _preloadAdmobModel = admobModel
        print("-->toj: admob激励广告: 预加载广告 响应 成功")
    }
    
    /* 加载广告回调 */
    func responseLoadAd(admobModel: STAdmobModel,
                        adObject: AdObject?,
                        error: Error?) {
        _loadedGAd = adObject
        
        if let error = error {
            print("-->toj: admob激励广告 加载失败: \(error.localizedDescription). unitID: \(admobModel.materials)")
            return
        }
        
        _admobModel = admobModel
        print("-->toj: admob激励广告 加载成功")
    }
    
    /* 清除广告 */
    func clearAd() {
        print("-->toj: admob激励 清除广告")
        _loadedGAd = nil
    }
    
    /* 激励广告发放奖励结果回调, 特有 */
    func userDidEarnRewardHandler() {
        _admobModel?.isShowed = true
    }
}

extension STRewardedAdmobObject {
    private func startLoadingTimer() {
        guard loadingTimer == nil else { return }
        
        loadingTimer = Timer.st_scheduledTimer(timeInterval: loadingTimeout, target: self, selector: #selector(loadingTimerCallBack))
    }
    
    private func stopLoadingTimer() {
        loadingTimer?.invalidate()
        loadingTimer = nil
    }
    
    @objc private func loadingTimerCallBack() {
        // guard let window = UIApplication.shared.keyWindow else { return }
        // window.loadingView.hide()
        stopLoadingTimer()
    }
}

// MARK: - 广告 GADFullScreenContentDelegate 回调
extension STRewardedAdmobObject: GADFullScreenContentDelegate {
    
    // 广告展示
    func adWillPresentFullScreenContent(_ ad: GADFullScreenPresentingAd) {
        print("-->toj: admob激励广告 广告展示")
        
        startTime = CFAbsoluteTimeGetCurrent()
        
        loadState.insert(.showing)
        delegate?.admobObjectDidPresentContent(self, admobModel: _admobModel)
    }
    
    // 广告展示失败
    func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
        print("-->toj: admob激励广告 广告展示失败")
        
        delegate?.admobObject(self, admobModel: _admobModel, didFailToPresentFullScreenContent: error)
        clearAd()
    }
    
    // 广告即将退出
    func adWillDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
        print("-->toj: admob激励广告 广告即将退出")
        
        let endTime = CFAbsoluteTimeGetCurrent()
        let showedTime = endTime - startTime
        print("-->toj: admob激励广告 time:\(showedTime)")
        
        delegate?.admobObjectWillDismissComplete(self, admobModel: _admobModel, showedTime: showedTime)
    }
    
    // 广告退出
    func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
        print("-->toj: admob激励广告 广告退出")
        delegate?.admobObjectDidDismissComplete(self, admobModel: _admobModel)
        clearAd()
        
        //print("-->toj: r adDidDismissFullScreenContent")
        guard let admobModel = _admobModel else { return }
        
        if !admobModel.isShowed { return }

        // 预加载下个广告
        let preloadAdmobModel = _preloadAdmobModel ?? admobModel
        preloadCacheAd(admobModel: preloadAdmobModel)
    }
    
    // 广告点击
    func adDidRecordClick(_ ad: GADFullScreenPresentingAd) {
        print("-->toj: admob激励广告 广告点击")
        delegate?.admobObjectDidRecordClick(self, admobModel: _admobModel)
    }
}
